#include<iostream>
#include<string>
#include<unistd.h>
#include<pthread.h>


#define TNUM 4
using namespace std;

typedef void(*func_t)(const string& name,pthread_mutex_t* pmtx,pthread_cond_t* pcond);
volatile bool quit = false;

class ThreadDate
{
public:
    ThreadDate(const string& name,func_t func,pthread_mutex_t* pmtx,pthread_cond_t* pcond)
    :name_(name),func_(func),pmtx_(pmtx),pcond_(pcond)
    {}
public:
    string name_;
    func_t func_;
    pthread_mutex_t* pmtx_;
    pthread_cond_t* pcond_;
};

void func1(const string& name,pthread_mutex_t* pmtx,pthread_cond_t* pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        cout<<name<<" is running---a"<<endl;
        pthread_mutex_unlock(pmtx);
        sleep(1);
    }
}

void func2(const string& name,pthread_mutex_t* pmtx,pthread_cond_t* pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        cout<<name<<" is running---b"<<endl;
        pthread_mutex_unlock(pmtx);
        sleep(1);
    }
}

void func3(const string& name,pthread_mutex_t* pmtx,pthread_cond_t* pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        cout<<name<<" is running---c"<<endl;
        pthread_mutex_unlock(pmtx);
        sleep(1);
    }
}

void func4(const string& name,pthread_mutex_t* pmtx,pthread_cond_t* pcond)
{
    while(!quit)
    {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond,pmtx);
        cout<<name<<" is running---d"<<endl;
        pthread_mutex_unlock(pmtx);
        sleep(1);
    }
}

void* Entry(void* args)
{
    ThreadDate* td = (ThreadDate*)args;
    td->func_(td->name_,td->pmtx_,td->pcond_);
    delete td;
    return nullptr;
}
int main()
{
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    pthread_mutex_init(&mtx,nullptr);
    pthread_cond_init(&cond,nullptr);
    pthread_t tids[TNUM];
    func_t funcs[TNUM]={func1,func2,func3,func4};
    for(int i=0;i<TNUM;i++)
    {
        string name = "thread ";
        name += to_string(i+1);
        ThreadDate* td = new ThreadDate(name,funcs[i],&mtx,&cond);
        pthread_create(tids + i,nullptr,Entry,(void*)td);
    }

    sleep(2);

    int cnt = 8;
    while(cnt)
    {
        cout<<"唤醒线程中..."<<cnt--<<endl;
        pthread_cond_signal(&cond);
        //pthread_cond_broadcast(&cond);
        sleep(1);
    }

    cout<<"线程控制结束"<<endl;
    quit=true;
    //pthread_cond_signal(&cond);
    pthread_cond_broadcast(&cond);
    for(int i = 0;i<TNUM;i++)
    {
        pthread_join(tids[i],nullptr);
        cout<<tids[i]<<" quit"<<endl;
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);
    return 0;
}